using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Services;
using Matrix.ServiceDiscovery.Contracts.Dtos;

namespace Matrix.ServiceDiscovery.Caching
{
    /// <summary>
    /// 服务发现缓存键定义
    /// </summary>
    public static class ServiceDiscoveryCacheKeys
    {
        private const string CacheKeyPrefix = "ServiceDiscovery";

        public static string GetServiceInfoKey(string serviceName, Guid? tenantId)
            => $"{CacheKeyPrefix}:ServiceInfo:{serviceName}:{tenantId?.ToString() ?? "global"}";

        public static string GetServiceListKey(GetServiceListInput input, Guid? tenantId)
        {
            var key = $"{CacheKeyPrefix}:ServiceList:{tenantId?.ToString() ?? "global"}";

            if (!input.Keyword.IsNullOrWhiteSpace())
                key += $":keyword:{input.Keyword}";

            if (!input.Category.IsNullOrWhiteSpace())
                key += $":category:{input.Category}";

            if (input.Status.HasValue)
                key += $":status:{input.Status}";

            key += $":skip:{input.SkipCount}:take:{input.MaxResultCount}";

            return key;
        }

        public static string GetHealthyInstancesKey(string serviceName, Guid? tenantId)
            => $"{CacheKeyPrefix}:HealthyInstances:{serviceName}:{tenantId?.ToString() ?? "global"}";

        public static string GetAllInstancesKey(string serviceName, Guid? tenantId)
            => $"{CacheKeyPrefix}:AllInstances:{serviceName}:{tenantId?.ToString() ?? "global"}";

        public static string GetStatisticsKey(string serviceName, Guid? tenantId)
            => $"{CacheKeyPrefix}:Statistics:{serviceName}:{tenantId?.ToString() ?? "global"}";

        public static string GetAllStatisticsKey(Guid? tenantId)
            => $"{CacheKeyPrefix}:AllStatistics:{tenantId?.ToString() ?? "global"}";

        public static string GetLoadBalancingConfigKey(string serviceName, Guid? tenantId)
            => $"{CacheKeyPrefix}:LoadBalancingConfig:{serviceName}:{tenantId?.ToString() ?? "global"}";

        public static string GetServiceExistsKey(string serviceName, Guid? tenantId)
            => $"{CacheKeyPrefix}:ServiceExists:{serviceName}:{tenantId?.ToString() ?? "global"}";

        public static string GetHealthyCountKey(Guid serviceId)
            => $"{CacheKeyPrefix}:HealthyCount:{serviceId}";

        public static string GetTotalCountKey(Guid serviceId)
            => $"{CacheKeyPrefix}:TotalCount:{serviceId}";
    }

    /// <summary>
    /// 服务发现缓存服务
    /// 实现L1本地缓存 + L2分布式缓存的多级缓存架构
    /// </summary>
    public class ServiceDiscoveryCacheService : DomainService, IScopedDependency
    {
        private readonly IMemoryCache _localCache;
        private readonly IDistributedCache<List<ServiceInstanceDto>> _distributedCache;
        private readonly IDistributedCache<ServiceInfoDto> _serviceInfoCache;
        private readonly IDistributedCache<List<ServiceInfoDto>> _serviceListCache;
        private readonly ILogger<ServiceDiscoveryCacheService> _logger;

        // L1本地缓存 - 超高频访问的微秒级响应
        private static readonly TimeSpan _localCacheExpiration = TimeSpan.FromMinutes(5);
        private static readonly TimeSpan _distributedCacheExpiration = TimeSpan.FromMinutes(30);

        public ServiceDiscoveryCacheService(
            IMemoryCache localCache,
            IDistributedCache<List<ServiceInstanceDto>> distributedCache,
            IDistributedCache<ServiceInfoDto> serviceInfoCache,
            IDistributedCache<List<ServiceInfoDto>> serviceListCache,
            ILogger<ServiceDiscoveryCacheService> logger)
        {
            _localCache = localCache;
            _distributedCache = distributedCache;
            _serviceInfoCache = serviceInfoCache;
            _serviceListCache = serviceListCache;
            _logger = logger;
        }

        /// <summary>
        /// 获取或设置缓存值 - 智能多级缓存策略
        /// </summary>
        public async Task<T?> GetOrSetAsync<T>(
            string cacheKey,
            Func<Task<T>> factory,
            TimeSpan? absoluteExpiration = null,
            TimeSpan? slidingExpiration = null) where T : class
        {
            // 1. L1本地缓存查询（微秒级响应）
            if (_localCache.TryGetValue(cacheKey, out T? localValue))
            {
                _logger.LogDebug("L1缓存命中: {CacheKey}", cacheKey);
                return localValue;
            }

            // 2. L2分布式缓存查询（毫秒级响应）
            T? distributedValue = await GetDistributedCacheAsync<T>(cacheKey);
            if (distributedValue != null)
            {
                // 回填L1缓存
                _localCache.Set(cacheKey, distributedValue, _localCacheExpiration);
                _logger.LogDebug("L2缓存命中，已回填L1缓存: {CacheKey}", cacheKey);
                return distributedValue;
            }

            // 3. 从数据源加载并缓存
            var value = await factory();

            // 设置双重缓存
            await SetAsync(cacheKey, value, absoluteExpiration, slidingExpiration);

            _logger.LogDebug("缓存未命中，已从数据源加载并缓存: {CacheKey}", cacheKey);
            return value;
        }

        /// <summary>
        /// 设置缓存值
        /// </summary>
        public async Task SetAsync<T>(
            string cacheKey,
            T value,
            TimeSpan? absoluteExpiration = null,
            TimeSpan? slidingExpiration = null) where T : class
        {
            if (value == null) return;

            // 设置L1本地缓存
            var cacheOptions = new MemoryCacheEntryOptions();
            if (slidingExpiration.HasValue)
                cacheOptions.SlidingExpiration = slidingExpiration.Value;
            else
                cacheOptions.AbsoluteExpirationRelativeToNow = absoluteExpiration ?? _localCacheExpiration;

            _localCache.Set(cacheKey, value, cacheOptions);

            // 设置L2分布式缓存
            await SetDistributedCacheAsync(cacheKey, value, absoluteExpiration);
        }

        /// <summary>
        /// 移除缓存值
        /// </summary>
        public async Task RemoveAsync(string cacheKey)
        {
            // 移除L1缓存
            _localCache.Remove(cacheKey);

            // 移除L2缓存
            await RemoveDistributedCacheAsync(cacheKey);

            _logger.LogDebug("已移除缓存: {CacheKey}", cacheKey);
        }

        /// <summary>
        /// 按模式批量移除缓存
        /// </summary>
        public async Task RemoveByPatternAsync(string pattern)
        {
            // 这里简化实现，实际项目中可以维护缓存键列表
            // 或者使用Redis的SCAN命令等高级功能
            _logger.LogDebug("按模式移除缓存: {Pattern}", pattern);

            // 移除匹配的L1缓存项
            // 遍历本地缓存并移除匹配项（简化实现）
            var keysToRemove = GetLocalCacheKeysByPattern(pattern);
            foreach (var key in keysToRemove)
            {
                _localCache.Remove(key);
            }

            // 对于分布式缓存，这里需要具体的实现
            // 例如Redis的KEYS或SCAN命令
        }

        /// <summary>
        /// 获取缓存统计信息
        /// </summary>
        public async Task<CacheStatisticsDto> GetCacheStatisticsAsync()
        {
            return new CacheStatisticsDto
            {
                GeneratedAt = Clock.Now,
                LocalCacheEntries = GetLocalCacheEntryCount(),
                DistributedCacheStatus = await GetDistributedCacheStatusAsync()
            };
        }

        #region Private Methods

        private async Task<T?> GetDistributedCacheAsync<T>(string cacheKey) where T : class
        {
            return cacheKey switch
            {
                var key when key.Contains("ServiceInfo") => await _serviceInfoCache.GetAsync(cacheKey) as T,
                var key when key.Contains("ServiceList") => await _serviceListCache.GetAsync(cacheKey) as T,
                var key when key.Contains("Instances") => await _distributedCache.GetAsync(cacheKey) as T,
                _ => null
            };
        }

        private async Task SetDistributedCacheAsync<T>(string cacheKey, T value, TimeSpan? absoluteExpiration) where T : class
        {
            var options = new Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow = absoluteExpiration ?? _distributedCacheExpiration
            };

            switch (value)
            {
                case ServiceInfoDto serviceInfo:
                    await _serviceInfoCache.SetAsync(cacheKey, serviceInfo, options);
                    break;
                case List<ServiceInfoDto> serviceList:
                    await _serviceListCache.SetAsync(cacheKey, serviceList, options);
                    break;
                case List<ServiceInstanceDto> instances:
                    await _distributedCache.SetAsync(cacheKey, instances, options);
                    break;
            }
        }

        private async Task RemoveDistributedCacheAsync(string cacheKey)
        {
            switch (cacheKey)
            {
                case var key when key.Contains("ServiceInfo"):
                    await _serviceInfoCache.RemoveAsync(cacheKey);
                    break;
                case var key when key.Contains("ServiceList"):
                    await _serviceListCache.RemoveAsync(cacheKey);
                    break;
                case var key when key.Contains("Instances"):
                    await _distributedCache.RemoveAsync(cacheKey);
                    break;
            }
        }

        private List<string> GetLocalCacheKeysByPattern(string pattern)
        {
            // 简化实现：返回空列表
            // 实际项目中可以通过反射或其他方式获取MemoryCache中的键
            return new List<string>();
        }

        private int GetLocalCacheEntryCount()
        {
            // 简化实现：MemoryCache不直接提供计数方法
            // 实际项目中可以通过反射或维护键列表来实现
            return 0;
        }

        private async Task<Dictionary<string, object>> GetDistributedCacheStatusAsync()
        {
            try
            {
                // 测试分布式缓存连接
                var testKey = $"cache:health:test:{Guid.NewGuid()}";
                var testValue = DateTime.UtcNow.ToString();

                await _serviceInfoCache.SetAsync(testKey, new ServiceInfoDto { Name = testValue },
                    new Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions
                    {
                        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1)
                    });

                var retrievedValue = await _serviceInfoCache.GetAsync(testKey);
                await _serviceInfoCache.RemoveAsync(testKey);

                return new Dictionary<string, object>
                {
                    ["Status"] = "Healthy",
                    ["LastTest"] = Clock.Now,
                    ["TestPassed"] = retrievedValue?.Name == testValue
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "分布式缓存健康检查失败");
                return new Dictionary<string, object>
                {
                    ["Status"] = "Unhealthy",
                    ["Error"] = ex.Message,
                    ["LastTest"] = Clock.Now
                };
            }
        }

        #endregion
    }

    /// <summary>
    /// 缓存统计信息DTO
    /// </summary>
    public class CacheStatisticsDto
    {
        public DateTime GeneratedAt { get; set; }
        public int LocalCacheEntries { get; set; }
        public Dictionary<string, object> DistributedCacheStatus { get; set; } = new();
    }
}